﻿//******************************************************************************************************
//  MeasurementLookup.cs - Gbtc
//
//  Copyright © 2010, Grid Protection Alliance.  All Rights Reserved.
//
//  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
//  the NOTICE file distributed with this work for additional information regarding copyright ownership.
//  The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
//  not use this file except in compliance with the License. You may obtain a copy of the License at:
//
//      http://www.opensource.org/licenses/eclipse-1.0.php
//
//  Unless agreed to in writing, the subject software distributed under the License is distributed on an
//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
//  License for the specific language governing permissions and limitations.
//
//  Code Modification History:
//  ----------------------------------------------------------------------------------------------------
//  10/05/2012 - Adam Crain
//       Generated original version of source code.
//  10/8/2012 - Danyelle Gilliam
//        Modified Header
//  12/26/2012 - Prasanna Kumari
//       Applied changes for Migrating adapters from the Time Series Framework to SIEGate Core
//
//******************************************************************************************************

using DNP3.Interface;
using GSF.TimeSeries;
using System;
using System.Collections.Generic;
using SIEGate.Core.Legacy;
using SIEGate.Core.Configurator;
using SIEGate.Core.Measurements.Values;

namespace Dnp3Adapters
{
    /// <summary>
    /// Helper class that converts measurements and provides a lookup capbility
    /// </summary>
    class MeasurementLookup
    {
        public MeasurementLookup(MeasurementMap map)
        {
            map.binaryMap.ForEach(m => binaryMap.Add(m.dnpIndex, m));
            map.analogMap.ForEach(m => analogMap.Add(m.dnpIndex, m));
            map.counterMap.ForEach(m => counterMap.Add(m.dnpIndex, m));
            map.controlStatusMap.ForEach(m => controlStatusMap.Add(m.dnpIndex, m));
            map.setpointStatusMap.ForEach(m => setpointStatusMap.Add(m.dnpIndex, m));
        }

        public ILegacyMeasurement LookupMaybeNull(Binary meas, UInt32 index)
        {
            return LookupMaybeNull<Binary>(meas, index, binaryMap, ConvertBinary);
        }

        public ILegacyMeasurement LookupMaybeNull(Analog meas, UInt32 index)
        {
            return LookupMaybeNull<Analog>(meas, index, analogMap, ConvertAnalog);
        }

        public ILegacyMeasurement LookupMaybeNull(Counter meas, UInt32 index)
        {
            return LookupMaybeNull<Counter>(meas, index, counterMap, ConvertCounter);
        }

        public ILegacyMeasurement LookupMaybeNull(ControlStatus meas, UInt32 index)
        {
            return LookupMaybeNull<ControlStatus>(meas, index, controlStatusMap, ConvertControlStatus);
        }

        public ILegacyMeasurement LookupMaybeNull(SetpointStatus meas, UInt32 index)
        {
            return LookupMaybeNull<SetpointStatus>(meas, index, setpointStatusMap, ConvertSetpointStatus);
        }

        private LegacyMeasurement ConvertBinary(Binary meas, uint id, String source)
        {
            var m = new LegacyMeasurement();
            m.Key = new MeasurementKey(Guid.Empty, id, source);
            //m.Value = meas.value ? 1.0 : 0.0;       //commented out since it's read-only
            m.Timestamp = DateTime.UtcNow;
            return m;
        }

        private LegacyMeasurement ConvertAnalog(Analog meas, uint id, String source)
        {
            var m = new LegacyMeasurement();
            m.Key = new MeasurementKey(Guid.Empty, id, source);
            //m.Value = meas.value;   
            ((LegacyValue)m.Value).SetRaw(meas.value);      //changes to handle cases of Value assignment
            m.Timestamp = DateTime.UtcNow;
            return m;
        }

        private LegacyMeasurement ConvertCounter(Counter meas, uint id, String source)
        {
            var m = new LegacyMeasurement();
            m.Key = new SIEGate.Core.Legacy.MeasurementKey(Guid.Empty, id, source);
            //m.Value = meas.value; //auto cast to double          //commented out since the property is read-only
            m.Timestamp = DateTime.UtcNow;
            return m;
        }

        private LegacyMeasurement ConvertControlStatus(ControlStatus meas, uint id, String source)
        {
            var m = new LegacyMeasurement();
            m.Key = new MeasurementKey(Guid.Empty, id, source);
            //m.Value = meas.value ? 1.0 : 0.0;                   //commented out since it's read-only
            m.Timestamp = DateTime.UtcNow;
            return m;
        }

        private LegacyMeasurement ConvertSetpointStatus(SetpointStatus meas, uint id, String source)
        {
            var m = new LegacyMeasurement();
            m.Key = new MeasurementKey(Guid.Empty, id, source);
            ((LegacyValue)m.Value).SetRaw(meas.value);      //changes to handle cases of Value assignment
            m.Timestamp = DateTime.UtcNow;
            return m;
        }

        private static ILegacyMeasurement LookupMaybeNull<T>(T meas, UInt32 index, Dictionary<UInt32, Mapping> map, Func<T, uint, String, LegacyMeasurement> converter)
        {
            Mapping id;
            if (map.TryGetValue(index, out id)) return converter(meas, id.tsfId, id.tsfSource);
            else return null;
        }

        private Dictionary<UInt32, Mapping> binaryMap = new Dictionary<uint, Mapping>();
        private Dictionary<UInt32, Mapping> analogMap = new Dictionary<uint, Mapping>();
        private Dictionary<UInt32, Mapping> counterMap = new Dictionary<uint, Mapping>();
        private Dictionary<UInt32, Mapping> controlStatusMap = new Dictionary<uint, Mapping>();
        private Dictionary<UInt32, Mapping> setpointStatusMap = new Dictionary<uint, Mapping>();
    }
}
